#ifndef __TPS_MSVC_TYPEOF_H__
#define __TPS_MSVC_TYPEOF_H__

#ifdef _MSC_VER

#include "tps_tl.h"

namespace Tps
{

	namespace Private
	{

		template <typename Id, typename T>
		struct TypeRegistry;

		template <typename Id>
		struct TypeRegistry<Id, NullType>
		{
			template<bool>
			struct IdToTypeImpl;
			typedef IdToTypeImpl<true> IdToType;
		};

		template <typename Id, typename T>
		struct TypeRegistry
			: public TypeRegistry<Id, NullType>
		{
			template <>
			struct IdToTypeImpl<true>
			{
				typedef T Type;
			};
		};

		template <typename Id, typename T>
		struct RegistryTypeItem
			: TypeRegistry<Id, T>
		{
			enum { TypeId = Id::Int };
		};

		char (& TypeItemIndex (...))[1];

		#define TPS_TYPEOF_NEXT_INDEX(next__) \
			friend char (& TypeItemIndex (TypeItem<next__> *))[next__];

		template<typename T>
		struct Sizer
		{
			enum { CurIndex = sizeof(TypeItemIndex(reinterpret_cast<TypeItem<300> *>(0))) };
			TPS_TYPEOF_NEXT_INDEX(CurIndex + 1);
			enum { NextIndex = sizeof(TypeItemIndex(reinterpret_cast<TypeItem<CurIndex + 1> *>(0))) };
			TPS_TYPEOF_NEXT_INDEX(NextIndex + 1);

			typedef char (&Array)[RegistryTypeItem<IntToType<CurIndex>, T>::TypeId];
		};

		template <typename T>
		typename Sizer<T>::Array GetSizerArray(T);

	}

}

#define TPS_TYPEOF(expr__) \
	Tps::Private::TypeRegistry<Tps::Private::IntToType<sizeof(Tps::Private::GetSizerArray(expr__))>, Tps::Private::NullType>::IdToType::Type

#endif	// !_MSC_VER

#endif	// !__TPS_MSVC_TYPEOF_H__
